using FlatRedBall;
using FlatRedBall.Math.Geometry;
using FlatRedBall.Input;
using FlatRedBall.Graphics.Animation;
using FlatRedBall.Math;

using Microsoft.Xna.Framework.Audio;

using Xzipit.Utilities;
using Xzipit.Interfaces;
using Microsoft.Xna.Framework.Input.Touch;
using FlatRedBall.Graphics;
using Xzipit.Utilities.Gestures;
using Microsoft.Xna.Framework;
using Xzipit.Utilities.Touch;

namespace Xzipit.GameObjects
{
    class Buckle : Obstacle, IPinchable
    {
        #region Fields

        private int _type;
        private int _openTime;
        private double _startTime;
        private double _elapsedTime;
        private Circle _pinchCollision;

        private SoundEffect _openSound;
        private Text _timeText;

        private float _spriteRotation;
        
        // Keep the ContentManager for easy access:
        string _contentManagerName;

        #endregion

        #region Properties
        // All properties of Button are already covered in Obstacle.

        #endregion

        #region Methods

        // Constructor
        public Buckle(string contentManagerName)
        {
            // Default constructor for testing purposes only.
            _contentManagerName = contentManagerName;
            _type = 1;
            _openTime = 0;

            Initialize(true);
        }

        public Buckle(string contentManagerName, float x, float y, int type, 
                      float rot, int openTime)
        {
            // Used to read in a buckle from a level file.
            _contentManagerName = contentManagerName;
            _type = type;
            this.Position.X = x;
            this.Position.Y = y;
            this.Position.Z = 0.1f;
            _spriteRotation = rot;
            _openTime = openTime;

            Initialize(true);
        }

        protected override void Initialize(bool addToManagers)
        {
            if (addToManagers)
            {
                AddToManagers();
            }
        }

        public virtual void AddToManagers()
        {
            SpriteManager.AddPositionedObject(this);

            InitializeAnimations();

            base.AddToManagers(0.8f, 1.0f);
            _startTime = 0;
            _elapsedTime = 0;

            // Creates a collision box used for detecting pinches inside the Buckle. It
            // is a circle that has a radius of the x scale of the sprite to give ample
            // room for users to pinch.
            _pinchCollision = ShapeManager.AddCircle();
            _pinchCollision.AttachTo(_sprite, false);
            _pinchCollision.Radius = _sprite.ScaleX * .6f;
            _pinchCollision.Visible = false;

            // The indicator that comes on screen if it is a tutorial level.
            SetTooltip("pinch");
            _tooltip.RelativeY = 2.0f;
            _tooltip.RelativeX = 1.0f;
            _tooltip.RelativeZ = 0.15f;

            _enabled = true;

            _timeText = TextManager.AddText("0", GameProperties.CustomFont);
            _timeText.Alpha = 0.0f;
            _timeText.Scale = 1.0f;
            _timeText.Spacing = 1.0f;
            _timeText.SetColor(0.8f, 0.0f, 0.0f);
            _timeText.AttachTo(this, false);
            _timeText.RelativeZ = 0.5f;
            

            // Load the sound effect for opening the buckle.
            _openSound = FlatRedBallServices.Load<SoundEffect>(@"Content\Sound\buckle");

            TouchManager.AddPinchable(this);
        }

        private void InitializeAnimations()
        {
            // Loads the animation chain for when the buckle opens.
            AnimationChainList ani = new AnimationChainList();
            AnimationChain opening = new AnimationChain();
            AnimationChain closing = new AnimationChain();

            for (int i = 1; i <= 6; i++)
            {
                opening.Add(new AnimationFrame(@"Content/GameObjects/Obstacles/Buckle/buckle" + i, 0.06f, "Global"));
            }
            opening.Name = "opening";

            for (int i = 6; i >= 1; i--)
            {
                closing.Add(new AnimationFrame(@"Content/GameObjects/Obstacles/Buckle/buckle" + i, 0.06f, "Global"));
            }
            closing.Name = "closing";

            ani.Add(opening);
            ani.Add(closing);

            _sprite = SpriteManager.AddSprite(ani);
            _sprite.CurrentChainName = "opening";
            _sprite.Animate = false;
            _sprite.RelativeRotationZ = _spriteRotation;
            _sprite.CurrentFrameIndex = 0;
        }

        public override void Activity(GameGesture zipGesture, double t)
        {
            // Terminate the animation of the sprite if it has reached the end.
            if (_sprite.JustCycled)
            {
                _sprite.Animate = false;
                _sprite.CurrentFrameIndex = 5;
            }
            if (!_enabled && _openTime != 0)
            {
                // get the amount of time that has elapsed since last update
                _elapsedTime = t - _startTime;
                Countdown();
            }

            if (_tooltip.Visible)
            {
                PlayTooltip();
            }


        }

        public override void Collide(double t)
        {
            return;
        }

        public override void Destroy()
        {
            base.Destroy();

            ShapeManager.Remove(_pinchCollision);
            TextManager.RemoveText(_timeText);

            TouchManager.RemovePinchable(this);
        }

        #endregion

        #region Private Methods

        // Flashes the tap this indicator.
        protected override void PlayTooltip()
        {
            if (_tooltip.Alpha <= 0.6f)
            {
                _tooltip.AlphaRate = 0.5f;
            }
            else if (_tooltip.Alpha >= 1.0f)
            {
                _tooltip.AlphaRate = -0.5f;
            }
        }

        private void Countdown()
        {
            if (_elapsedTime >= _openTime)
            {
                _sprite.CurrentChainName = "closing";
                _sprite.CurrentFrameIndex = 0;
                _sprite.Animate = true;
                _openSound.PlaySound();
                _enabled = true;

                _timeText.Alpha = 1.0f;
                _timeText.DisplayText = "0";
                _timeText.AlphaRate = -1.0f;

                _elapsedTime = 0;
            }
            else
            {
                int displayTime = _openTime - (int)_elapsedTime;
                if (!_timeText.DisplayText.Equals(displayTime.ToString()))
                {
                    _timeText.Alpha = 1.0f;
                    _timeText.DisplayText = displayTime.ToString();
                    _timeText.AlphaRate = -1.0f;
                }
            }
        }

        #endregion

        #region Gesture Management

        public bool WasPinched(GameGesture g)
        {
            Circle pos = ShapeManager.AddCircle();
            pos.Position = g.End;
            pos.Radius = 2.0f;
            bool result = (g.GameGestureType == GameGestureType.Pinch) 
                && _pinchCollision.CollideAgainst(pos)
                && _enabled;
            ShapeManager.Remove(pos);
            return result;
        }

        public void OnPinch()
        {
            // Animate buckle and play sound.
            _sprite.CurrentChainName = "opening";
            _sprite.CurrentFrameIndex = 0;
            _sprite.Animate = true;
            _openSound.PlaySound();
            _enabled = false;
            _tooltip.Visible = false;
        }

        public void OnPinch(double startTime)
        {
            // Animate buckle and play sound.
            _sprite.CurrentChainName = "opening";
            _sprite.CurrentFrameIndex = 0;
            _sprite.Animate = true;
            _openSound.PlaySound();
            _enabled = false;
            _startTime = startTime;
            _tooltip.Visible = false;
        }

        #endregion 
    }
}
